home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Tools 2
/
Amiga Tools 2.iso
/
tools
/
vim
/
src
/
unix.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-09
|
30KB
|
1,488 lines
/* vi:ts=4:sw=4
*
* VIM - Vi IMproved by Bram Moolenaar
*
* Read the file "credits.txt" for a list of people who contributed.
* Read the file "uganda.txt" for copying and usage conditions.
*/
/*
* unix.c -- BSD and SYSV code
*
* A lot of this file was written by Juergen Weigert.
*/
#include "vim.h"
#include "globals.h"
#include "param.h"
#include "proto.h"
#include <fcntl.h>
#if !defined(pyr) && !defined(NOT_BOTH_TIME)
# include <time.h> /* on some systems time.h should not be
included together with sys/time.h */
#endif
#include <sys/ioctl.h>
#ifndef M_XENIX
# include <sys/types.h>
#endif
#include <signal.h>
#ifndef USE_SYSTEM /* use fork/exec to start the shell */
# include <sys/wait.h>
# if !defined(SCO) && !defined(SOLARIS) && !defined(hpux) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(_SEQUENT_) && !defined(UNISYS) /* SCO returns pid_t */
extern int fork();
# endif
# if !defined(linux) && !defined(SOLARIS) && !defined(USL) && !defined(sun) && !(defined(hpux) && defined(__STDC__)) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(USL) && !defined(UNISYS)
extern int execvp __ARGS((const char *, const char **));
# endif
#endif
#if defined(SYSV_UNIX) || defined(USL)
# if defined(__sgi) || defined(UTS2) || defined(UTS4) || defined(MIPS) || defined (MIPSEB) || defined(__osf__)
# include <sys/time.h>
# endif
# if defined(M_XENIX) || defined(SCO)
# include <stropts.h>
# endif
# if defined(M_XENIX) || defined(SCO) || defined(UNICOS)
# include <sys/select.h>
# define bzero(a, b) memset((a), 0, (b))
# endif
# if !defined(M_XENIX) && !defined(UNICOS)
# include <poll.h>
# endif
# if defined(SCO) || defined(ISC)
# include <sys/stream.h>
# include <sys/ptem.h>
# endif
# if defined(M_UNIX) && !defined(SCO)
# include <sys/time.h>
# endif /* M_UNIX */
# ifdef ISC
# include <termios.h>
# endif
# include <termio.h>
#else /* SYSV_UNIX */
# include <sys/time.h>
# if defined(hpux) || defined(linux)
# include <termio.h>
# if defined(hpux) && !defined(SIGWINCH) /* hpux 9.01 has it */
# define SIGWINCH SIGWINDOW
# endif
# else
# include <sgtty.h>
# endif /* hpux */
#endif /* !SYSV_UNIX */
#if (defined(pyr) || defined(NO_FD_ZERO)) && defined(SYSV_UNIX) && defined(FD_ZERO)
# undef FD_ZERO
#endif
#if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
# ifdef SIGWINCH
# undef SIGWINCH
# endif
# ifdef TIOCGWINSZ
# undef TIOCGWINSZ
# endif
#endif
#ifdef USE_X11
# include <X11/Xlib.h>
# include <X11/Xutil.h>
Window x11_window = 0;
Display *x11_display = NULL;
static int get_x11_windis __ARGS((void));
#ifdef BUGGY
static void set_x11_title __ARGS((char_u *));
static void set_x11_icon __ARGS((char_u *));
#endif
#endif
static void get_x11_title __ARGS((void));
static void get_x11_icon __ARGS((void));
static int Read __ARGS((char_u *, long));
static int WaitForChar __ARGS((int));
static int RealWaitForChar __ARGS((int));
static void fill_inbuf __ARGS((void));
#ifdef USL
static void sig_winch __ARGS((int));
#else
# if defined(SIGWINCH) && !defined(linux) && !defined(__alpha) && !defined(mips) && !defined(_SEQUENT_) && !defined(SCO) && !defined(SOLARIS) && !defined(ISC)
static void sig_winch __ARGS((int, int, struct sigcontext *));
# endif
#endif
static int do_resize = FALSE;
static char_u *oldtitle = NULL;
static char_u *oldicon = NULL;
static char_u *extra_shell_arg = NULL;
static int show_shell_mess = TRUE;
/*
* At this point TRUE and FALSE are defined as 1L and 0L, but we want 1 and 0.
*/
#undef TRUE
#define TRUE 1
#undef FALSE
#define FALSE 0
void
mch_write(s, len)
char_u *s;
int len;
{
write(1, (char *)s, len);
}
/*
* GetChars(): low level input funcion.
* Get a characters from the keyboard.
* If wtime == 0 do not wait for characters.
* If wtime == n wait a short time for characters.
* If wtime == -1 wait forever for characters.
*/
int
GetChars(buf, maxlen, wtime)
char_u *buf;
int maxlen;
int wtime; /* don't use "time", MIPS cannot handle it */
{
int len;
if (wtime >= 0)
{
while (WaitForChar(wtime) == 0) /* no character available */
{
if (!do_resize) /* return if not interrupted by resize */
return 0;
set_winsize(0, 0, FALSE);
do_resize = FALSE;
}
}
else /* wtime == -1 */
{
/*
* If there is no character available within 'updatetime' seconds
* flush all the swap files to disk
* Also done when interrupted by SIGWINCH.
*/
if (WaitForChar((int)p_ut) == 0)
updatescript(0);
}
for (;;) /* repeat until we got a character */
{
if (do_resize) /* window changed size */
{
set_winsize(0, 0, FALSE);
do_resize = FALSE;
}
/*
* we want to be interrupted by the winch signal
*/
WaitForChar(-1);
if (do_resize) /* interrupted by SIGWINCHsignal */
continue;
len = Read(buf, (long)maxlen);
if (len > 0)
return len;
}
}
/*
* return non-zero if a character is available
*/
int
mch_char_avail()
{
return WaitForChar(0);
}
long
mch_avail_mem(special)
int special;
{
return 0x7fffffff; /* virual memory eh */
}
#ifndef FD_ZERO
void
vim_delay()
{
poll(0, 0, 500);
}
#else
# if (defined(__STDC__) && !defined(hpux)) || defined(ultrix)
extern int select __ARGS((int, fd_set *, fd_set *, fd_set *, struct timeval *));
# endif
void
vim_delay()
{
struct timeval tv;
tv.tv_sec = 25 / 50;
tv.tv_usec = (25 % 50) * (1000000/50);
select(0, 0, 0, 0, &tv);
}
#endif
static void
#if defined(__alpha) || (defined(mips) && !defined(USL))
sig_winch()
#else
# if defined(_SEQUENT_) || defined(SCO) || defined(ISC)
sig_winch(sig, code)
int sig;
int code;
# else
# if defined(USL)
sig_winch(sig)
int sig;
# else
sig_winch(sig, code, scp)
int sig;
int code;
struct sigcontext *scp;
# endif
# endif
#endif
{
#if defined(SIGWINCH)
/* this is not required on all systems, but it doesn't hurt anybody */
signal(SIGWINCH, (void (*)())sig_winch);
#endif
do_resize = TRUE;
}
/*
* If the machine has job control, use it to suspend the program,
* otherwise fake it by starting a new shell.
*/
void
mch_suspend()
{
#ifdef SIGTSTP
settmode(0);
kill(0, SIGTSTP); /* send ourselves a STOP signal */
settmode(1);
#else
OUTSTR("new shell started\n");
(void)call_shell(NULL, 0, TRUE);
#endif
}
void
mch_windinit()
{
Columns = 80;
Rows = 24;
flushbuf();
(void)mch_get_winsize();
#if defined(SIGWINCH)
signal(SIGWINCH, (void (*)())sig_winch);
#endif
}
/*
* Check_win checks whether we have an interactive window.
* If not, a new window is opened with the newcli command.
* If we would open a window ourselves, the :sh and :! commands would not
* work properly (Why? probably because we are then running in a background CLI).
* This also is the best way to assure proper working in a next Workbench release.
*
* For the -e option (quickfix mode) we open our own window and disable :sh.
* Otherwise we would never know when editing is finished.
*/
#define BUF2SIZE 320 /* lenght of buffer for argument with complete path */
void
check_win(argc, argv)
int argc;
char **argv;
{
if (!isatty(0) || !isatty(1))
{
fprintf(stderr, "VIM: no controlling terminal\n");
exit(2);
}
}
/*
* fname_case(): Set the case of the filename, if it already exists.
* This will cause the filename to remain exactly the same.
*/
void
fname_case(name)
char_u *name;
{
}
#ifdef USE_X11
/*
* try to get x11 window and display
*
* return FAIL for failure, OK otherwise
*/
static int
get_x11_windis()
{
char *winid;
/*
* If WINDOWID not set, should try another method to find out
* what the current window number is. The only code I know for
* this is very complicated.
* We assume that zero is invalid for WINDOWID.
*/
if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
x11_window = (Window)atol(winid);
if (x11_window != 0 && x11_display == NULL)
x11_display = XOpenDisplay(NULL);
if (x11_window == 0 || x11_display == NULL)
return FAIL;
return OK;
}
/*
* Determine original x11 Window Title
*/
static void
get_x11_title()
{
XTextProperty text_prop;
if (get_x11_windis() == OK)
{
/* Get window name if any */
if (XGetWMName(x11_display, x11_window, &text_prop))
{
if (text_prop.value != NULL)
oldtitle = strsave((char_u *)text_prop.value);
XFree((void *)text_prop.value);
}
}
if (oldtitle == NULL) /* could not get old title */
oldtitle = (char_u *)"Thanks for flying Vim";
}
/*
* Determine original x11 Window icon
*/
static void
get_x11_icon()
{
XTextProperty text_prop;
if (get_x11_windis() == OK)
{
/* Get icon name if any */
if (XGetWMIconName(x11_display, x11_window, &text_prop))
{
if (text_prop.value != NULL)
oldicon = strsave((char_u *)text_prop.value);
XFree((void *)text_prop.value);
}
}
/* could not get old icon, use terminal name */
if (oldicon == NULL)
{
if (STRNCMP(term_strings.t_name, "builtin_", 8) == 0)
oldicon = term_strings.t_name + 8;
else
oldicon = term_strings.t_name;
}
}
#if BUGGY
This is not included, because it probably does not work at all.
On my FreeBSD/Xfree86 in a shelltool I get all kinds of error messages and
Vim is stopped in an uncontrolled way.
/*
* Set x11 Window Title
*
* get_x11_windis() must be called before this and have returned OK
*/
static void
set_x11_title(title)
char_u *title;
{
XTextProperty text_prop;
/* Get icon name if any */
text_prop.value = title;
text_prop.nitems = STRLEN(title);
XSetWMName(x11_display, x11_window, &text_prop);
if (XGetWMName(x11_display, x11_window, &text_prop)) /* required? */
XFree((void *)text_prop.value);
}
/*
* Set x11 Window icon
*
* get_x11_windis() must be called before this and have returned OK
*/
static void
set_x11_icon(icon)
char_u *icon;
{
XTextProperty text_prop;
/* Get icon name if any */
text_prop.value = icon;
text_prop.nitems = STRLEN(icon);
XSetWMIconName(x11_display, x11_window, &text_prop);
if (XGetWMIconName(x11_display, x11_window, &text_prop)) /* required? */
XFree((void *)text_prop.value);
}
#endif
#else /* USE_X11 */
static void
get_x11_title()
{
oldtitle = (char_u *)"Thanks for flying Vim";
}
static void
get_x11_icon()
{
if (STRNCMP(term_strings.t_name, "builtin_", 8) == 0)
oldicon = term_strings.t_name + 8;
else
oldicon = term_strings.t_name;
}
#endif /* USE_X11 */
/*
* set the window title and icon
* Currently only works for x11.
*/
void
mch_settitle(title, icon)
char_u *title;
char_u *icon;
{
int type = 0;
if (term_strings.t_name == NULL) /* no terminal name (yet) */
return;
/*
* if the window ID and the display is known, we may use X11 calls
*/
#ifdef USE_X11
if (get_x11_windis() == OK)
type = 1;
#endif
/*
* note: if terminal is xterm, title is set with escape sequence rather
* than x11 calls, because the x11 calls don't always work
*/
if ( STRCMP(term_strings.t_name, "xterm") == 0 ||
STRCMP(term_strings.t_name, "builtin_xterm") == 0)
type = 2;
/*
* Note: getting the old window title for iris-ansi will only
* currently work if you set WINDOWID by hand, it is not
* done automatically like an xterm.
*/
if (STRCMP(term_strings.t_name, "iris-ansi") == 0 ||
STRCMP(term_strings.t_name, "iris-ansi-net") == 0)
type = 3;
if (type)
{
if (title != NULL)
{
if (oldtitle == NULL) /* first call, save title */
get_x11_title();
switch(type)
{
#ifdef USE_X11
#ifdef BUGGY
case 1: set_x11_title(title); /* x11 */
break;
#endif
#endif
case 2: outstrn((char_u *)"\033]2;"); /* xterm */
outstrn(title);
outchar(Ctrl('G'));
flushbuf();
break;
case 3: outstrn((char_u *)"\033P1.y"); /* iris-ansi */
outstrn(title);
outstrn((char_u *)"\234");
flushbuf();
break;
}
}
if (icon != NULL)
{
if (oldicon == NULL) /* first call, save icon */
get_x11_icon();
switch(type)
{
#ifdef USE_X11
#ifdef BUGGY
case 1: set_x11_icon(icon); /* x11 */
break;
#endif
#endif
case 2: outstrn((char_u *)"\033]1;"); /* xterm */
outstrn(icon);
outchar(Ctrl('G'));
flushbuf();
break;
case 3: outstrn((char_u *)"\033P3.y"); /* iris-ansi */
outstrn(icon);
outstrn((char_u *)"\234");
flushbuf();
break;
}
}
}
}
/*
* Restore the window/icon title.
* which is one of:
* 1 Just restore title
* 2 Just restore icon
* 3 Restore title and icon
*/
void
mch_restore_title(which)
int which;
{
mch_settitle((which & 1) ? oldtitle : NULL, (which & 2) ? oldicon : NULL);
}
/*
* Get name of current directory into buffer 'buf' of length 'len' bytes.
* Return OK for success, FAIL for failure.
*/
int
vim_dirname(buf, len)
char_u *buf;
int len;
{
#if defined(SYSV_UNIX) || defined(USL) || defined(hpux) || defined(linux)
extern int errno;
extern char *sys_errlist[];
if (getcwd((char *)buf, len) == NULL)
{
STRCPY(buf, sys_errlist[errno]);
return FAIL;
}
return OK;
#else
return (getwd((char *)buf) != NULL ? OK : FAIL);
#endif
}
/*
* get absolute filename into buffer 'buf' of length 'len' bytes
*
* return FAIL for failure, OK for success
*/
int
FullName(fname, buf, len)
char_u *fname, *buf;
int len;
{
int l;
char_u olddir[MAXPATHL];
char_u *p;
int c;
int retval = OK;
if (fname == NULL) /* always fail */
{
*buf = NUL;
return FAIL;
}
*buf = 0;
if (!isFullName(fname)) /* if not an absolute path */
{
/*
* If the file name has a path, change to that directory for a moment,
* and then do the getwd() (and get back to where we were).
* This will get the correct path name with "../" things.
*/
if ((p = STRRCHR(fname, '/')) != NULL)
{
#if defined(SYSV_UNIX) || defined(USL) || defined(hpux) || defined(linux)
if (getcwd((char *)olddir, MAXPATHL) == NULL)
#else
if (getwd((char *)olddir) == NULL)
#endif
{
p = NULL; /* can't get current dir: don't chdir */
retval = FAIL;
}
else
{
c = *p;
*p = NUL;
if (chdir((char *)fname))
retval = FAIL;
else
fname = p + 1;
*p = c;
}
}
#if defined(SYSV_UNIX) || defined(USL) || defined(hpux) || defined(linux)
if (getcwd((char *)buf, len) == NULL)
#else
if (getwd((char *)buf) == NULL)
#endif
{
retval = FAIL;
*buf = NUL;
}
l = STRLEN(buf);
if (l && buf[l - 1] != '/')
STRCAT(buf, "/");
if (p)
chdir((char *)olddir);
}
STRCAT(buf, fname);
return retval;
}
/*
* return TRUE is fname is an absolute path name
*/
int
isFullName(fname)
char_u *fname;
{
return (*fname == '/');
}
/*
* get file permissions for 'name'
*/
long
getperm(name)
char_u *name;
{
struct stat statb;
if (stat((char *)name, &statb))
return -1;
return statb.st_mode;
}
/*
* set file permission for 'name' to 'perm'
*
* return FAIL for failure, OK otherwise
*/
int
setperm(name, perm)
char_u *name;
int perm;
{
#ifdef SCO
return (chmod((char *)name, (mode_t)perm) == 0 ? OK : FAIL);
#else
return (chmod((char *)name, perm) == 0 ? OK : FAIL);
#endif
}
/*
* return TRUE if "name" is a directory
* return FALSE if "name" is not a directory
* return -1 for error
*/
int
isdir(name)
char_u *name;
{
struct stat statb;
if (stat((char *)name, &statb))
return -1;
#ifdef _POSIX_SOURCE
return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
#else
return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
#endif
}
void
mch_windexit(r)
int r;
{
settmode(0);
exiting = TRUE;
mch_settitle(oldtitle, oldicon); /* restore xterm title */
stoptermcap();
flushbuf();
ml_close_all(); /* remove all memfiles */
exit(r);
}
void
mch_settmode(raw)
int raw;
{
#if defined(ECHOE) && defined(ICANON) && !defined(__NeXT__)
/* for "new" tty systems */
# ifdef CONVEX
static struct termios told;
struct termios tnew;
# else
static struct termio told;
struct termio tnew;
# endif
#ifdef TIOCLGET
static unsigned long tty_local;
#endif
if (raw)
{
#ifdef TIOCLGET
ioctl(0, TIOCLGET, &tty_local);
#endif
ioctl(0, TCGETA, &told);
tnew = told;
/*
* ICRNL enables typing ^V^M
*/
tnew.c_iflag &= ~ICRNL;
tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
#ifdef IEXTEN
| IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
#endif
);
tnew.c_cc[VMIN] = 1; /* return after 1 char */
tnew.c_cc[VTIME] = 0; /* don't wait */
ioctl(0, TCSETA, &tnew);
}
else
{
ioctl(0, TCSETA, &told);
#ifdef TIOCLGET
ioctl(0, TIOCLSET, &tty_local);
#endif
}
#else
# ifndef TIOCSETN
# define TIOCSETN TIOCSETP /* for hpux 9.0 */
# endif
/* for "old" tty systems */
static struct sgttyb ttybold;
struct sgttyb ttybnew;
if (raw)
{
ioctl(0, TIOCGETP, &ttybold);
ttybnew = ttybold;
ttybnew.sg_flags &= ~(CRMOD | ECHO);
ttybnew.sg_flags |= RAW;
ioctl(0, TIOCSETN, &ttybnew);
}
else
ioctl(0, TIOCSETN, &ttybold);
#endif
}
/*
* set screen mode, always fails.
*/
int
mch_screenmode(arg)
char_u *arg;
{
EMSG("Screen mode setting not supported");
return FAIL;
}
/*
* Try to get the current window size:
* 1. with an ioctl(), most accurate method
* 2. from the environment variables LINES and COLUMNS
* 3. from the termcap
* 4. keep using the old values
*/
int
mch_get_winsize()
{
int old_Rows = Rows;
int old_Columns = Columns;
char_u *p;
Columns = 0;
Rows = 0;
/*
* 1. try using an ioctl. It is the most accurate method.
*/
# ifdef TIOCGSIZE
{
struct ttysize ts;
if (ioctl(0, TIOCGSIZE, &ts) == 0)
{
Columns = ts.ts_cols;
Rows = ts.ts_lines;
}
}
# else /* TIOCGSIZE */
# ifdef TIOCGWINSZ
{
struct winsize ws;
if (ioctl(0, TIOCGWINSZ, &ws) == 0)
{
Columns = ws.ws_col;
Rows = ws.ws_row;
}
}
# endif /* TIOCGWINSZ */
# endif /* TIOCGSIZE */
/*
* 2. get size from environment
*/
if (Columns == 0 || Rows == 0)
{
if ((p = (char_u *)getenv("LINES")))
Rows = atoi((char *)p);
if ((p = (char_u *)getenv("COLUMNS")))
Columns = atoi((char *)p);
}
#ifdef TERMCAP
/*
* 3. try reading the termcap
*/
if (Columns == 0 || Rows == 0)
{
extern void getlinecol();
getlinecol(); /* get "co" and "li" entries from termcap */
}
#endif
/*
* 4. If everything fails, use the old values
*/
if (Columns <= 0 || Rows <= 0)
{
Columns = old_Columns;
Rows = old_Rows;
return FAIL;
}
check_winsize();
/* if size changed: screenalloc will allocate new screen buffers */
return OK;
}
void
mch_set_winsize()
{
/* should try to set the window size to Rows and Columns */
}
int
call_shell(cmd, dummy, cooked)
char_u *cmd;
int dummy;
int cooked;
{
#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
int x;
char_u newcmd[1024];
flushbuf();
if (cooked)
settmode(0); /* set to cooked mode */
if (cmd == NULL)
x = system(p_sh);
else
{
sprintf(newcmd, "%s %s -c \"%s\"", p_sh,
extra_shell_arg == NULL ? "" : extra_shell_arg, cmd);
x = system(newcmd);
}
if (x == 127)
{
outstrn((char_u *)"\nCannot execute shell sh\n");
}
#ifdef WEBB_COMPLETE
else if (x && !expand_interactively)
#else
else if (x)
#endif
{
outchar('\n');
outnum((long)x);
outstrn((char_u *)" returned\n");
}
if (cooked)
settmode(1); /* set to raw mode */
resettitle();
return (x ? FAIL : OK);
#else /* USE_SYSTEM */ /* first attempt at not using system() */
char_u newcmd[1024];
int pid;
int status = -1;
char **argv = NULL;
int argc;
int i;
char_u *p;
int inquote;
flushbuf();
signal(SIGINT, SIG_IGN); /* we don't want to be killed here */
if (cooked)
settmode(0); /* set to cooked mode */
/*
* 1: find number of arguments
* 2: separate them and built argv[]
*/
STRCPY(newcmd, p_sh);
for (i = 0; i < 2; ++i)
{
p = newcmd;
inquote = FALSE;
argc = 0;
for (;;)
{
if (i == 1)
argv[argc] = (char *)p;
++argc;
while (*p && (inquote || (*p != ' ' && *p != TAB)))
{
if (*p == '"')
inquote = !inquote;
++p;
}
if (*p == NUL)
break;
if (i == 1)
*p++ = NUL;
skipspace(&p);
}
if (i == 0)
{
argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
if (argv == NULL) /* out of memory */
goto error;
}
}
if (cmd != NULL)
{
if (extra_shell_arg != NULL)
argv[argc++] = (char *)extra_shell_arg;
argv[argc++] = "-c";
argv[argc++] = (char *)cmd;
}
argv[argc] = NULL;
if ((pid = fork()) == -1) /* maybe we should use vfork() */
{
outstrn((char_u *)"\nCannot fork\n");
}
else if (pid == 0) /* child */
{
signal(SIGINT, SIG_DFL);
if (!show_shell_mess)
{
fclose(stdout);
fclose(stderr);
}
execvp(argv[0], (char **)argv);
exit(127); /* exec failed, return failure code */
}
else /* parent */
{
wait(&status);
status = (status >> 8) & 255;
if (status)
{
#ifdef WEBB_COMPLETE
if (status == 127)
{
outstrn((char_u *)"\nCannot execute shell ");
outstrn(p_sh);
outchar('\n');
}
else if (!expand_interactively)
{
outchar('\n');
outnum((long)status);
outstrn((char_u *)" returned\n");
}
#else
outchar('\n');
if (status == 127)
{
outstrn((char_u *)"Cannot execute shell ");
outstrn(p_sh);
}
else
{
outnum((long)status);
outstrn((char_u *)" returned");
}
outchar('\n');
#endif /* WEBB_COMPLETE */
}
}
free(argv);
error:
if (cooked)
settmode(1); /* set to raw mode */
resettitle();
signal(SIGINT, SIG_DFL);
return (status ? FAIL : OK);
#endif /* USE_SYSTEM */
}
/*
* The input characters are buffered to be able to check for a CTRL-C.
* This should be done with signals, but I don't know how to do that in
* a portable way for a tty in RAW mode.
*/
#define INBUFLEN 250
static char_u inbuf[INBUFLEN]; /* internal typeahead buffer */
static int inbufcount = 0; /* number of chars in inbuf[] */
static int
Read(buf, maxlen)
char_u *buf;
long maxlen;
{
if (inbufcount == 0) /* if the buffer is empty, fill it */
fill_inbuf();
if (maxlen > inbufcount)
maxlen = inbufcount;
memmove((char *)buf, (char *)inbuf, maxlen);
inbufcount -= maxlen;
if (inbufcount)
memmove((char *)inbuf, (char *)inbuf + maxlen, inbufcount);
return (int)maxlen;
}
void
breakcheck()
{
/*
* check for CTRL-C typed by reading all available characters
*/
if (RealWaitForChar(0)) /* if characters available */
fill_inbuf();
}
static void
fill_inbuf()
{
int len;
if (inbufcount >= INBUFLEN) /* buffer full */
return;
len = read(0, inbuf + inbufcount, (long)(INBUFLEN - inbufcount));
if (len <= 0) /* cannot read input??? */
{
fprintf(stderr, "Vim: Error reading input, exiting...\n");
exit(1);
}
while (len-- > 0)
{
/*
* if a CTRL-C was typed, remove it from the buffer and set got_int
*/
if (inbuf[inbufcount] == 3)
{
/* remove everything typed before the CTRL-C */
memmove((char *)inbuf, (char *)inbuf + inbufcount, len + 1);
inbufcount = 0;
got_int = TRUE;
}
++inbufcount;
}
}
/*
* Wait "ticks" until a character is available from the keyboard or from inbuf[]
* ticks = -1 will block forever
*/
static int
WaitForChar(ticks)
int ticks;
{
if (inbufcount) /* something in inbuf[] */
return 1;
return RealWaitForChar(ticks);
}
/*
* Wait "ticks" until a character is available from the keyboard
* ticks = -1 will block forever
*/
static int
RealWaitForChar(ticks)
int ticks;
{
#ifndef FD_ZERO
struct pollfd fds;
fds.fd = 0;
fds.events = POLLIN;
return (poll(&fds, 1, ticks));
#else
struct timeval tv;
fd_set fdset;
if (ticks >= 0)
{
tv.tv_sec = ticks / 1000;
tv.tv_usec = (ticks % 1000) * (1000000/1000);
}
FD_ZERO(&fdset);
FD_SET(0, &fdset);
return (select(1, &fdset, NULL, NULL, (ticks >= 0) ? &tv : NULL));
#endif
}
#if !defined(__alpha) && !defined(mips) && !defined(SCO) && !defined(remove) && !defined(CONVEX)
int
remove(buf)
# if defined(linux) || defined(__STDC__) || defined(__NeXT__) || defined(M_UNIX)
const
# endif
char *buf;
{
return unlink(buf);
}
#endif
/*
* ExpandWildCard() - this code does wild-card pattern matching using the shell
*
* Mool: return 0 for success, 1 for error (you may loose some memory) and
* put an error message in *file.
*
* num_pat is number of input patterns
* pat is array of pointers to input patterns
* num_file is pointer to number of matched file names
* file is pointer to array of pointers to matched file names
* On Unix we do not check for files only yet
* list_notfound is ignored
*/
extern char *mktemp __ARGS((char *));
#ifndef SEEK_SET
# define SEEK_SET 0
#endif
#ifndef SEEK_END
# define SEEK_END 2
#endif
int
ExpandWildCards(num_pat, pat, num_file, file, files_only, list_notfound)
int num_pat;
char_u **pat;
int *num_file;
char_u ***file;
int files_only;
int list_notfound;
{
char_u tmpname[TMPNAMELEN];
char_u *command;
int i;
int dir;
size_t len;
FILE *fd;
char_u *buffer;
char_u *p;
int use_glob = FALSE;
*num_file = 0; /* default: no files found */
*file = (char_u **)"";
/*
* If there are no wildcards, just copy the names to allocated memory.
* Saves a lot of time, because we don't have to start a new shell.
*/
if (!have_wildcard(num_pat, pat))
{
*file = (char_u **)alloc(num_pat * sizeof(char_u *));
if (*file == NULL)
{
*file = (char_u **)"";
return FAIL;
}
for (i = 0; i < num_pat; i++)
(*file)[i] = strsave(pat[i]);
*num_file = num_pat;
return OK;
}
/*
* get a name for the temp file
*/
STRCPY(tmpname, TMPNAME2);
if (*mktemp((char *)tmpname) == NUL)
{
emsg(e_notmp);
return FAIL;
}
/*
* let the shell expand the patterns and write the result into the temp file
* If we use csh, glob will work better than echo.
*/
if ((len = STRLEN(p_sh)) >= 3 && STRCMP(p_sh + len - 3, "csh") == 0)
use_glob = TRUE;
len = TMPNAMELEN + 11;
for (i = 0; i < num_pat; ++i) /* count the length of the patterns */
len += STRLEN(pat[i]) + 3;
command = alloc(len);
if (command == NULL)
return FAIL;
if (use_glob)
STRCPY(command, "glob >"); /* built the shell command */
else
STRCPY(command, "echo >"); /* built the shell command */
STRCAT(command, tmpname);
for (i = 0; i < num_pat; ++i)
{
#ifdef USE_SYSTEM
STRCAT(command, " \""); /* need extra quotes because we */
STRCAT(command, pat[i]); /* start the shell twice */
STRCAT(command, "\"");
#else
STRCAT(command, " ");
STRCAT(command, pat[i]);
#endif
}
#ifdef WEBB_COMPLETE
if (expand_interactively)
show_shell_mess = FALSE;
#endif /* WEBB_COMPLETE */
if (use_glob) /* Use csh fast option */
extra_shell_arg = (char_u *)"-f";
i = call_shell(command, 0, FALSE); /* execute it */
extra_shell_arg = NULL;
show_shell_mess = TRUE;
free(command);
if (i == FAIL) /* call_shell failed */
{
remove((char *)tmpname);
#ifdef WEBB_COMPLETE
/* With interactive completion, the error message is not printed */
if (!expand_interactively)
#endif /* WEBB_COMPLETE */
{
must_redraw = CLEAR; /* probably messed up screen */
msg_outchar('\n'); /* clear bottom line quickly */
cmdline_row = Rows - 1; /* continue on last line */
}
return FAIL;
}
/*
* read the names from the file into memory
*/
fd = fopen((char *)tmpname, "r");
if (fd == NULL)
{
emsg2(e_notopen, tmpname);
return FAIL;
}
fseek(fd, 0L, SEEK_END);
len = ftell(fd); /* get size of temp file */
fseek(fd, 0L, SEEK_SET);
buffer = alloc(len + 1);
if (buffer == NULL)
{
remove((char *)tmpname);
fclose(fd);
return FAIL;
}
i = fread((char *)buffer, 1, len, fd);
fclose(fd);
remove((char *)tmpname);
if (i != len)
{
emsg2(e_notread, tmpname);
free(buffer);
return FAIL;
}
if (use_glob) /* file names are separated with NUL */
{
buffer[len] = NUL; /* make sure the buffers ends in NUL */
i = 0;
for (p = buffer; p < buffer + len; ++p)
if (*p == NUL) /* count entry */
++i;
if (len)
++i; /* count last entry */
}
else /* file names are separated with SPACE */
{
buffer[len] = '\n'; /* make sure the buffers ends in NL */
p = buffer;
for (i = 0; *p != '\n'; ++i) /* count number of entries */
{
while (*p != ' ' && *p != '\n') /* skip entry */
++p;
skipspace(&p); /* skip to next entry */
}
}
*num_file = i;
*file = (char_u **)alloc(sizeof(char_u *) * i);
if (*file == NULL)
{
free(buffer);
*file = (char_u **)"";
return FAIL;
}
p = buffer;
for (i = 0; i < *num_file; ++i)
{
(*file)[i] = p;
if (use_glob)
{
while (*p && p < buffer + len) /* skip entry */
++p;
++p; /* skip NUL */
}
else
{
while (*p != ' ' && *p != '\n') /* skip entry */
++p;
if (*p == '\n') /* last entry */
*p = NUL;
else
{
*p++ = NUL;
skipspace(&p); /* skip to next entry */
}
}
}
for (i = 0; i < *num_file; ++i)
{
dir = (isdir((*file)[i]) == TRUE);
if (dir < 0) /* if file doesn't exist don't add '/' */
dir = 0;
p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
if (p)
{
STRCPY(p, (*file)[i]);
if (dir)
STRCAT(p, "/");
}
(*file)[i] = p;
}
free(buffer);
return OK;
}
void
FreeWild(num, file)
int num;
char_u **file;
{
if (file == NULL || num == 0)
return;
while (num--)
free(file[num]);
free(file);
}
int
has_wildcard(p)
char_u *p;
{
#ifdef __STDC__
return strpbrk((char *)p, "*?[{`~$") != NULL;
#else
for ( ; *p; ++p)
if (STRCHR("*?[{`~$", *p) != NULL)
return 1;
return 0;
#endif
}
int
have_wildcard(num, file)
int num;
char_u **file;
{
register int i;
for (i = 0; i < num; i++)
if (has_wildcard(file[i]))
return 1;
return 0;
}
#if defined(M_XENIX) || defined(UTS2)
/*
* Scaled-down version of rename, which is missing in Xenix.
* This version can only move regular files and will fail if the
* destination exists.
*/
int
rename(src, dest)
char_u *src, *dest;
{
struct stat st;
if (stat(dest, &st) >= 0) /* fail if destination exists */
return -1;
if (link(src, dest) != 0) /* link file to new name */
return -1;
if (unlink(src) == 0) /* delete link to old name */
return 0;
return -1;
}
#endif /* M_XENIX || UTS2 */